from typing import Dict, List, Any

from dotenv import load_dotenv
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory

from llm import llmConfig
from llm.llmHistory import get_session_history

# 加载环境变量
load_dotenv()


def intentRecognition(user_input: str, selected_template: List[str], session_id: str = "default") -> Dict[str, Any]:
    """
    意图识别和信息补充
    
    Args:
        user_input: 用户输入的问题
        selected_template: 选择的模板字段列表
        session_id: 会话ID，默认为'default'
        
    Returns:
        Dict[str, Any]: 包含处理结果的字典，格式为:
            {
                "isComplete": bool,  # 问题是否完整
                "content": str,      # 完整问题或提示信息
                "extracted_info": Optional[Dict[str, str]]  # 提取的信息(仅当完整时)
                "missing_fields": Optional[List[str]]  # 缺失的字段(仅当不完整时)
            }
    """
    # 补充信息提示模板
    info_prompt = f"""
        请根据用户原始问题和模板，判断原始问题是否完善。如果问题缺乏需要的信息，请生成一个友好的请求，明确指出需要补充的信息。若问题完善后，返回包含所有信息的完整问题。

        ### 原始问题    
        {user_input}

        ### 模板字段
        {",".join(selected_template)}                                   

        ### 输出格式
        {{
            "isComplete": true,
            "content": "完整问题内容",
            "extracted_info": {{
                "字段1": "对应值",
                "字段2": "对应值",
                // 包含模板中所有字段的提取结果
            }}
        }}
        
        或者
        
        {{
            "isComplete": false,
            "content": "友好的引导需要补充的信息",
            "missing_fields": ["缺失的字段1", "缺失的字段2"]
        }}                                       
    """

    # 聊天模版
    prompt = ChatPromptTemplate.from_messages(
        [
            ("system", "你是一个信息补充助手，任务是分析用户问题是否完整，并根据模板提取关键信息。"),
            MessagesPlaceholder(variable_name="chat_history"),
            ("human", "{input}")
        ]
    )

    # 创建LLM
    llm = llmConfig.getCommonLLM()

    # 创建基础链
    chain = prompt | llm

    # 添加消息历史
    chain_with_history = RunnableWithMessageHistory(
        chain,
        get_session_history=get_session_history,
        input_messages_key="input",
        history_messages_key="chat_history"
    )

    try:
        # 判断问题是否完整，如果不完整，则生成追问请求
        info_request = chain_with_history.invoke(
            input={"input": info_prompt},
            config={"configurable": {"session_id": session_id}}
        ).content

        parser = JsonOutputParser()
        try:
            json_data = parser.parse(info_request)
        except Exception as e:
            print(f"JSON解析错误: {str(e)}")
            json_data = {
                "isComplete": False,
                "content": "解析回复时出错，请重新描述您的问题。",
                "error": str(e)
            }

        # 当问题完整时，尝试提取结构化信息
        if json_data.get('isComplete') is True and 'extracted_info' not in json_data:
            extraction_prompt = f"""
                请从以下完整问题中提取关键信息，按照模板字段进行结构化。
                
                ### 完整问题
                {json_data['content']}
                
                ### 模板字段
                {",".join(selected_template)}
                
                ### 输出格式
                {{
                    "extracted_info": {{
                        "字段1": "对应值",
                        "字段2": "对应值",
                        // 模板中所有字段
                    }}
                }}
            """

            extraction_response = chain_with_history.invoke(
                input={"input": extraction_prompt},
                config={"configurable": {"session_id": session_id}}
            ).content

            try:
                extraction_data = parser.parse(extraction_response)
                if 'extracted_info' in extraction_data:
                    json_data['extracted_info'] = extraction_data['extracted_info']
            except Exception as e:
                print(f"信息提取错误: {str(e)}")
                # 提取失败不影响主流程

        return json_data

    except Exception as e:
        print(f"意图识别错误: {str(e)}")
        return {
            "isComplete": False,
            "content": f"处理您的问题时出错: {str(e)}",
            "error": str(e)
        }
